home *** CD-ROM | disk | FTP | other *** search
/ Symantec Visual Cafe for Java 2.5 / symantec-visual-cafe-2.5-database-dev-edition.iso / Visual Cafe Pro v1.0 / SOURCE.BIN / Matrix.java < prev    next >
Encoding:
Java Source  |  1997-06-19  |  14.8 KB  |  631 lines

  1. package symantec.itools.awt;
  2.  
  3. // ===================================================================================
  4. // = Revision History
  5. // ===================================================================================
  6.  
  7. // Matrix
  8. //        This class implements a sparse matrix of objects
  9. //        
  10.  
  11. // 03/20/97    RKM        Made the class public as per customer request
  12. //                    Removed bogus debugging code
  13. //                    Removed compaction of empty rows code
  14. // 03/27/97    RKM        Made class final (this class is not made to be extended)
  15. //                    Followed example of Vector, and added JavaDoc, throws, & synchronized
  16. //                    Made final
  17. //                    Tried to make some sense of protection on methods & members
  18. // 03/28/97    RKM        Un-privitized members
  19. // 05/02/97 RKM     Fixed removeRow - made it actually work
  20. // 05/02/97 RKM     Fixed insertRow - one of the loops was not checking for null
  21.  
  22. /**
  23.  * This class implements a sparse matrix of objects.
  24.  * @version 1.0, Nov 26, 1996
  25.  * @author    Symantec
  26.  */
  27.  
  28. public final class Matrix
  29. {
  30.     //--------------------------------------------------
  31.     // public constructors
  32.     //--------------------------------------------------
  33.     
  34.     /**
  35.      * Constructs an empty matrix.
  36.      */
  37.     public Matrix()
  38.     {
  39.         rowHead = this;
  40.     }
  41.     
  42.     //--------------------------------------------------
  43.     // private constructors
  44.     //--------------------------------------------------
  45.     
  46.     private Matrix(int r, int c, Object obj)
  47.     {
  48.         this(r, c, obj, null);
  49.     }
  50.     
  51.     private Matrix(int r, int c, Object obj, Matrix rh, Matrix nr, Matrix ne)
  52.     {
  53.         if (rh == null)
  54.         {
  55.             if (c != 0)
  56.             {
  57.                 rowHead = new Matrix(r, 0, null, null, nr, this);
  58.             }
  59.             else
  60.             {
  61.                 rowHead = this;
  62.             }
  63.         }
  64.         else
  65.         {
  66.             rowHead = rh;
  67.         }
  68.         
  69.         row = r;
  70.         col = c;
  71.         o = obj;
  72.         nextRow = nr;
  73.         nextElt = ne;
  74.     }
  75.     
  76.     private Matrix(int r, int c, Object obj, Matrix nr, Matrix ne)
  77.     {
  78.         this(r, c, obj, null, nr, ne);
  79.     }
  80.     
  81.     private Matrix(int r, int c, Object obj, Matrix nr)
  82.     {
  83.         this(r, c, obj, null, nr, null);
  84.     }
  85.     
  86.     //--------------------------------------------------
  87.     // public methods
  88.     //--------------------------------------------------
  89.     
  90.     /**
  91.      * Adds the specified object as the last element of the vector.
  92.      * @param r the row of the element to be added
  93.      * @param c the column of the element to added
  94.      * @param o the element to be added
  95.      * @exception IllegalArgumentException If the element is already allocated 
  96.      * @see #updateElement
  97.      */
  98.     public synchronized void addElement(int r, int c, Object o)
  99.         throws IllegalArgumentException
  100.     {
  101.         //find the correct row
  102.         Matrix m = nearest(r, c);
  103.     
  104.         if (m.row != r)
  105.         {
  106.             m.setNextRow(new Matrix(r, c, o, m.nextRow).rowHead);
  107.             return;
  108.         }
  109.     
  110.         //m must equal row
  111.         if (c == m.col && c == 0)
  112.         {
  113.             if (m.o != null)
  114.             {
  115.                 //exception - should call update
  116.                 throw new IllegalArgumentException("Element already in Matrix");
  117.             }
  118.             else
  119.             {
  120.                 m.o = o;
  121.                 return;
  122.             }
  123.         }
  124.     
  125.         m.nextElt = new Matrix(r, c, o, m.rowHead, m.nextRow, m.nextElt);
  126.     }
  127.     
  128.     /**
  129.      * Adds or updates the element at the specified index as needed.
  130.      * @param r the row of the element to be added
  131.      * @param c the column of the element to added
  132.      * @param o the element to be added
  133.      * @see #addElement
  134.      */
  135.     public synchronized void updateElement(int r, int c, Object obj)
  136.     {
  137.         Matrix m = nearest(r, c);
  138.     
  139.         try
  140.         {
  141.             if (m == null)
  142.             {
  143.                 //first element in matrix
  144.                 addElement(r, c, obj);
  145.             }
  146.             else if (m.row != r || m.col != c)
  147.             {
  148.                 m.addElement(r, c, obj);
  149.             }
  150.             else
  151.             {
  152.                 //must be the element
  153.                 m.o = obj;
  154.             }
  155.         }
  156.         catch(IllegalArgumentException iae)
  157.         {
  158.             iae.printStackTrace();
  159.         }
  160.     }
  161.     
  162.     /**
  163.      * Removes all elements of the matrix. The matrix becomes empty.
  164.      */
  165.     public synchronized void removeAllElements()
  166.     {
  167.         nextRow = null;
  168.         nextElt = null;
  169.         o = null;
  170.     }
  171.     
  172.     /**
  173.      * Returns the element at the specified index.
  174.      * @param r the row of the element to remove
  175.      * @param c the column of the element to remove
  176.      * @return the element at [r,c]
  177.      * @exception ArrayIndexOutOfBoundsException an invalid 
  178.      * row & column was given.
  179.      */
  180.     public synchronized Object elementAt(int r, int c)
  181.         throws ArrayIndexOutOfBoundsException
  182.     {
  183.         Matrix m = nearest(r, c);
  184.         
  185.         if (m == null || m.row != r || m.col != c || m.o == null)
  186.             throw new ArrayIndexOutOfBoundsException("Element row=" + r + " col=" + c + " is not in matrix");
  187.         
  188.         return m.o;
  189.     }
  190.     
  191.     /**
  192.      * Deletes the element at the specified index.
  193.      * @param r the row of the element to remove
  194.      * @param c the column of the element to remove
  195.      * @exception ArrayIndexOutOfBoundsException the index was invalid.
  196.      */
  197.     public synchronized void removeElementAt(int r, int c)
  198.         throws ArrayIndexOutOfBoundsException
  199.     {
  200.         Matrix m = nearest(r, c);
  201.         
  202.         if (m == null || m.row != r || m.col != c)
  203.             throw new ArrayIndexOutOfBoundsException("Element row=" + r + " col=" + c + " is not in matrix");
  204.         
  205.         if (c == 0)
  206.         {
  207.             m.o = null;
  208.             return;
  209.         }
  210.         
  211.         Matrix prev = m = m.rowHead;
  212.         
  213.         while(m.col != c)
  214.         {
  215.             prev = m;
  216.             m = m.nextElt;
  217.         }
  218.         
  219.         prev.nextElt = m.nextElt;
  220.     }
  221.     
  222.     /**
  223.      * Deletes all elements on the specified row.
  224.      * @param r the row of elements to remove
  225.      * @see #insertRow
  226.      * @see #removeElementAt
  227.      */
  228.     public synchronized void removeRow(int r)
  229.     {
  230.         //Removing zero is a special case, essentially we have to change this
  231.         if (r == 0)
  232.         {
  233.             this.o            = null;
  234.             this.nextElt    = null;
  235.             if (this.nextRow != null)
  236.             {
  237.                 //Remove new zero elem from the row list and assign its data into this
  238.                 Matrix newZeroElem = this.nextRow;
  239.                 this.nextRow    = newZeroElem.nextRow;
  240.                 this.nextElt    = newZeroElem.nextElt;
  241.                 this.row        = newZeroElem.row;
  242.                 this.col        = newZeroElem.col;
  243.                 this.o            = newZeroElem.o;
  244.                 
  245.                 //Hook up rowHeads of the elements in zero elem (since it's now this)
  246.                 {
  247.                     Matrix elemMatrix = this.nextElt;
  248.                     while (elemMatrix != null)
  249.                     {
  250.                         elemMatrix.rowHead = this;
  251.                         elemMatrix = elemMatrix.nextElt;
  252.                     }
  253.                 }
  254.                 
  255.                 //Decrement row of all matrixs
  256.                 Matrix stepMatrix = this;
  257.                 while (stepMatrix != null)
  258.                 {
  259.                     stepMatrix.updateRowNum(stepMatrix.row - 1);
  260.                     stepMatrix = stepMatrix.nextRow;
  261.                 }
  262.             }
  263.         }
  264.         else
  265.         {
  266.             //Find the matrix that comes before the row, if it exists
  267.             Matrix stepMatrix = this.nextRow;
  268.             Matrix lastRow = this;
  269.             while (stepMatrix != null && stepMatrix.row < r)
  270.             {
  271.                 lastRow = stepMatrix;
  272.                 stepMatrix = stepMatrix.nextRow;
  273.             }
  274.             
  275.             if (stepMatrix != null)
  276.             {
  277.                 //We have an explicit row matrix
  278.                 if (stepMatrix.row == r)
  279.                 {
  280.                     //Skip it in the chain
  281.                     lastRow.nextRow = stepMatrix.nextRow;
  282.                     
  283.                     //???RKM??? I thought I understood this class, until this was required
  284.                     //???RKM??? This is chicken blood - I don't know why it's here !!!
  285.                     stepMatrix.o = null;
  286.                     stepMatrix.nextElt = null;
  287.                     
  288.                     //Advance a row (number changing purposes)
  289.                     stepMatrix = stepMatrix.nextRow;
  290.                 }
  291.                 
  292.                 //Change the row numbers of all the remaining rows
  293.                 while (stepMatrix != null)
  294.                 {
  295.                     stepMatrix.updateRowNum(stepMatrix.row - 1);
  296.                     stepMatrix = stepMatrix.nextRow;
  297.                 }
  298.             }
  299.         }
  300.         
  301.         /* RKM Was
  302.         Matrix m = nearest(r, 0);
  303.     
  304.         if (m.row == r)
  305.         {
  306.             m = m.rowHead;
  307.             m.o = null;
  308.             m.nextElt = null;
  309.         }
  310.         */
  311.     }
  312.     
  313.     /**
  314.      * Inserts a new row by incrementing the row number of all elements with
  315.      * row indexes >= given row number.
  316.      * @param r the number of the row to insert
  317.      * @see #removeRow
  318.      */
  319.     public synchronized void insertRow(int r)
  320.     {
  321.         Matrix m, n;
  322.     
  323.         if (r == 0)
  324.         {
  325.             //???RKM??? I don't see how this can work ???
  326.             
  327.             //want to insert into first row
  328.             m = new Matrix();
  329.             m.setNextRow(this);
  330.         }
  331.         else
  332.         {
  333.             m = nearest(r-1, 0);
  334.             n = new Matrix(r, 0, null, m.nextRow);
  335.             m.setNextRow(n);
  336.             m = n;
  337.         }
  338.         
  339.         if (m.nextRow.row == r)
  340.         {
  341.             //slip and increment row numbers
  342.             m = m.nextRow;
  343.     
  344.             while(m != null)
  345.             {
  346.                 m.updateRowNum(++r);
  347.                 m = m.nextRow;
  348.                 if (m != null && m.row != r) return;
  349.             }
  350.         }
  351.     }
  352.     
  353.     /**
  354.      * Sorts all rows in ascending order by comparing elements at the given 
  355.      * column number using the provided CompareFunc.
  356.      * @param f compares two objects and determines which one is less than the other
  357.      * @param c the column number of elements to compare
  358.      */
  359.     public synchronized void sort(CompareFunc f, int c)
  360.     {
  361.         boolean first = true;
  362.         Matrix  m = this,
  363.                 n = null;
  364.     
  365.         while(m != null)
  366.         {
  367.             n = findLeast(f, m, c, first);
  368.     
  369.             if (n != null)
  370.             {
  371.                 if (m.row == 0 && first)
  372.                 {
  373.                     first = false;
  374.                     swapRows(n);
  375.                     m = this;
  376.                     continue;
  377.                  }
  378.                  else
  379.                  {
  380.                     swapRows(m, n);
  381.                  }
  382.             }
  383.     
  384.             if (first)
  385.             {
  386.                 first = false;
  387.                 continue;
  388.             }
  389.     
  390.             m = m.nextRow;
  391.         }
  392.     }
  393.  
  394.     /**
  395.      * Prints the specified row to System.out.
  396.      * @param r the row to print
  397.      */
  398.     public synchronized void printRow(int r)
  399.     {
  400.         Matrix m = nearest(r, 0);
  401.     
  402.         if (m.row != r)
  403.         {
  404.             m = m.nextRow;
  405.             if (m.row != r)
  406.             {
  407.                 System.out.println("Row " + r + " is not in the matrix");
  408.                 return;
  409.             }
  410.         }
  411.     
  412.         System.out.println("-------- Printing row " + r + " ----------");
  413.         while(m != null)
  414.         {
  415.             System.out.println("Row=" + m.row + "  Col=" + m.col + "  value=" + m.o);
  416.             m = m.nextElt;
  417.         }
  418.     }
  419.  
  420.     /**
  421.      * Returns the number of rows in the matrix.
  422.      */
  423.     public synchronized int rows()
  424.     {
  425.         Matrix m = this;
  426.         
  427.         while(m.nextRow != null)
  428.         {
  429.             m = m.nextRow;
  430.         }
  431.         
  432.         return (m.nextElt == null && m.o == null ? m.row : m.row+1);
  433.     }
  434.     
  435.     //only call on row head
  436.     private synchronized void updateRowNum(int r)
  437.     {
  438.         Matrix m = this;
  439.     
  440.         while(m != null)
  441.         {
  442.             m.row = r;
  443.             m = m.nextElt;
  444.         }
  445.     }
  446.     
  447.     /**
  448.      * Returns an enumeration of the elements. Use the Enumeration methods on
  449.      * the returned object to fetch the elements sequentially.
  450.      */
  451.     public synchronized MatrixEnumeration elements()
  452.     {
  453.         return new MatrixEnumeration(this);
  454.     }
  455.     
  456.     /**
  457.      * Returns a string representation of this component.
  458.      * This is a standard Java AWT method which gets called to generate
  459.      * a string that represents this component.
  460.      * 
  461.      * @return a meaningful string about this object
  462.      */
  463.     public synchronized String toString()
  464.     {
  465.         return "Matrix: row=" + row + " col=" + col + " o=" + o;
  466.     }
  467.     
  468.     //--------------------------------------------------
  469.     // private members
  470.     //--------------------------------------------------
  471.     
  472.     private synchronized Matrix nearest(int r, int c)
  473.     {
  474.         //find the correct row
  475.         Matrix m = this;
  476.     
  477.         while (r > m.row)
  478.         {
  479.             if (m.nextRow != null && m.nextRow.row <= r)
  480.             {
  481.                 //further down pike so keep climbing
  482.                 m = m.nextRow;
  483.             }
  484.             else
  485.             {
  486.                 return m;
  487.             }
  488.         }
  489.     
  490.         //m must equal row
  491.         while (m.nextElt != null && c >= m.nextElt.col)
  492.         {
  493.             //further down the line
  494.             m = m.nextElt;
  495.         }
  496.     
  497.         return m;
  498.     }
  499.     
  500.     private synchronized void setRowHead()
  501.     {
  502.         Matrix m = nextElt;
  503.         Matrix h = this;
  504.     
  505.         while (m != null)
  506.         {
  507.             m.rowHead = h;
  508.             m = m.nextElt;
  509.         }
  510.     }
  511.     
  512.     private synchronized void setNextRow(Matrix nr)
  513.     {
  514.         Matrix m = this;
  515.     
  516.         while(m != null)
  517.         {
  518.             m.nextRow = nr;
  519.             m = m.nextElt;
  520.         }
  521.     }
  522.     
  523.     //m1 & m2 preceed the two rows to be switched.
  524.     private synchronized void swapRows(Matrix p1, Matrix p2)
  525.     {
  526.         Matrix t1 = p1.nextRow;
  527.         Matrix t1NextRow = t1.nextRow;
  528.         Matrix t2 = p2.nextRow;
  529.         Matrix t2NextRow = t2.nextRow;
  530.     
  531.         p1.setNextRow(t2);
  532.         p2.setNextRow(t1);
  533.     
  534.         if (p2 == t1)
  535.         {
  536.             t2.setNextRow(t1);
  537.         }
  538.         else
  539.         {
  540.             t2.setNextRow(t1NextRow);
  541.         }
  542.     
  543.         t1.setNextRow(t2NextRow);
  544.         int t1Row = t1.row;
  545.         t1.updateRowNum(t2.row);
  546.         t2.updateRowNum(t1Row);
  547.     }
  548.     
  549.     //swap the current row (must be the first) with the row following m2
  550.     private synchronized void swapRows(Matrix m2)
  551.     {
  552.         Matrix t2 = m2.nextRow;
  553.         Matrix t1 = new Matrix(-1, t2.col, o, null, nextElt);
  554.         m2.rowHead.setNextRow(t1);
  555.         t1.setNextRow(t2.nextRow);
  556.         t1.updateRowNum(t2.row);
  557.         t1.setRowHead();
  558.         
  559.         //fixup root node (that is this)
  560.         nextElt = t2.nextElt;
  561.         o = t2.o;
  562.         setNextRow(nextRow);  //this.nextRow never changed so can use for update
  563.         updateRowNum(0);
  564.         setRowHead();
  565.     }
  566.     
  567.     private synchronized Matrix findLeast(CompareFunc f, Matrix m, int c, boolean first)
  568.     {
  569.         //m is row previous to one to be compared to when m.row != 0
  570.         if (!first)
  571.             m = m.nextRow;
  572.         
  573.         if(m == null || m.nextRow == null)
  574.             return null;
  575.         
  576.         Matrix n = m.nextRow.rowHead;
  577.         Matrix prevToN = m.rowHead;
  578.         Matrix prevToLeast = null;
  579.         
  580.         m = m.nearest(m.row, c);
  581.         
  582.         while (n != null)
  583.         {
  584.             n = n.nearest(n.row, c);
  585.         
  586.             if (n.col != c)
  587.             {
  588.                 //no item for column on next row so keep searching
  589.                 prevToN = n.rowHead;
  590.                 n = n.nextRow;
  591.                 continue;
  592.             }
  593.             else if (m.col != c)
  594.             {
  595.                 //no item for first column so automatically sent down
  596.                 m = n;
  597.                 prevToLeast = prevToN;
  598.                 continue;
  599.             }
  600.         
  601.             if (f.lessThan(n.o, m.o))
  602.             {
  603.                 //n < m so put n in for least
  604.                 m = n;
  605.                 prevToLeast = prevToN;
  606.             }
  607.         
  608.             prevToN = n.rowHead;
  609.             n = n.nextRow;
  610.         }
  611.         
  612.         return prevToLeast;
  613.     }
  614.     
  615.     //--------------------------------------------------
  616.     // private members
  617.     //--------------------------------------------------
  618.     
  619.     Matrix        rowHead;
  620.     Matrix        nextRow;
  621.     Matrix        nextElt;
  622.     int            row;
  623.     int            col;
  624.     Object        o;
  625. }
  626.  
  627. interface CompareFunc
  628. {
  629.     public abstract boolean lessThan(Object o1, Object o2);
  630. }
  631.